import Core.DataBase as DataBase
import Core.JDMySQLDB as JDMySQLDB
import Core.MAADB as MAADB
import pandas as pd
import datetime
from Core.Exception import *
import Core.TonghuashunDatabase as THSDatabase


def Common_Load_DailyBar_DataFrame(database, symbol, datetime1=None, datetime2=None, instrument_type=None):
    #
    # instrument_types = ["index", "stock", "mutualfund", "future", "bond", "simulatefof", "selfprod"]
    instrument_types = ["index", "stock", "mutualfund", "future"]
    current_instrument_type = instrument_type

    # 如果指定资产类型, 将目标资产类型优先级提前
    if instrument_type:
        instrument_type = instrument_type.lower()
        # if instrument_type in instrument_types:
        #     instrument_types.remove(instrument_type)
        # instrument_types.insert(0, instrument_type)
        # # instrument_types = [instrument_type]
        #
        df_bars = database.Get_Daily_Bar_DataFrame(symbol,
                                                   instrument_type=instrument_type,
                                                   datetime1=datetime1,
                                                   datetime2=datetime2)

    else:
        print("Common_Load_DailyBar_DataFrame::没有指定 instrument_type", symbol)

        # 循环所有可能类型 -- 读取时间增加 20%
        df_bars = pd.DataFrame()
        current_instrument_type = None
        for instrument_type in instrument_types:
            current_instrument_type = instrument_type
            # df_bars = database.Get_Daily_Bar_DataFrame(symbol, instrument_type=instrument_type) # 不加日期反倒会慢
            df_bars = database.Get_Daily_Bar_DataFrame(symbol,
                                                       instrument_type=instrument_type,
                                                       datetime1=datetime1,
                                                       datetime2=datetime2)
            if len(df_bars) > 0:
                break
    #
    if len(df_bars) == 0:
        print("Common_Load_DailyBar_DataFrame::没有找到数据", symbol, instrument_type, datetime1, datetime2)
        return pd.DataFrame()

    # 不必再指定时间区间
    # df_bars = df_bars[(df_bars["date"] >= datetime1) & (df_bars["date"] <= datetime2)]
    # if len(df_bars) == 0:
    #     # print("No Daily bar in Time Range", datetime1, datetime2, symbol, instrument_type)
    #     return pd.DataFrame()

    # 必要的适配
    if current_instrument_type == "mutualfund":
        df_bars.rename(columns={"adjusted_net_asset_value": "close"}, inplace=True)
    #
    elif current_instrument_type == "stock":
        if "bclose" in df_bars.columns:
            df_bars.rename(columns={"close": "close1"}, inplace=True)
            df_bars.rename(columns={"bclose": "close"}, inplace=True)
    #
    elif current_instrument_type in ["simulatefof", "selfprod"]:
        df_bars.rename(columns={"acc_net_val": "close"}, inplace=True)

    return df_bars[["date", "close", "symbol"]].copy(deep=True)


def Load_Multi_DailyBar_DataFrame(database, symbol_list, datetime1, datetime2, instrument_type_list=[], return_none=False):
    #
    loading_time1 = datetime.datetime.now()
    #
    support_instrument_type = False
    if len(instrument_type_list) > 0 and len(instrument_type_list) == len(symbol_list):
        support_instrument_type = True
    #
    data = []
    missing_symbols = []

    for i in range(len(symbol_list)):
        symbol = symbol_list[i]

        # 如果有可能的话，确定资产类型
        instrument_type = None
        if support_instrument_type:
            instrument_type = instrument_type_list[i]

        # 读取数据库
        df_bars = Common_Load_DailyBar_DataFrame(database, symbol, datetime1, datetime2, instrument_type)
        if df_bars.empty:
            missing_symbols.append(symbol)
            continue
        df_bars = df_bars[["date", "close"]].copy(deep=True)
        # header 从close改为symbol
        df_bars.rename(columns={"close": symbol}, inplace=True)
        df_bars.set_index("date", inplace=True)
        # print(df_bars)
        data.append(df_bars)
    #
    loading_time2 = datetime.datetime.now()
    print("Loading Time", (loading_time2 - loading_time1).total_seconds())
    #
    if len(missing_symbols) > 0 and not return_none:
        raise MissingDataException(missing_symbols)
    #
    if len(data) == 0:
        return pd.DataFrame()

    df = pd.concat(data, axis=1, sort=True)
    # print(df)
    return df


# 2020-8-19
# 用于多数据源融合
class UniDataInterface(DataBase.DataBase):

    def __init__(self, config):
        self.name = "UniDataInterface 融合数据库"
        print("建立数据库对象", self.name)
        self.config = config
        self.contexts = {}
        # JT2数据库
        maa_config = config["MAADB"]
        self.maa_database = MAADB.MAADB(maa_config["Address"],
                                        maa_config["Port"],
                                        maa_config["Username"],
                                        maa_config["Password"],
                                        maa_config["Database"])
        # 同花顺数据库
        ths_config = config["TongHuaShunDB"]
        self.ths_database = THSDatabase.THSDatabase(ths_config["Address"],
                                                    ths_config["Port"],
                                                    ths_config["Username"],
                                                    ths_config["Password"],
                                                    ths_config["Database"])

    def Get_Instruments(self, instrument_type, filter=[], projection=[], listed=True):
        if instrument_type:
            instrument_type = instrument_type.lower()

        if instrument_type in ["mutualfund", "stock", "index", "future", "bond"]:
            return self.ths_database.Get_Instruments(instrument_type, filter=filter, projection=projection)

    def Get_Instruments_DataFrame(self, instrument_type, filter=[], projection=[], listed=True):
        if instrument_type:
            instrument_type = instrument_type.lower()

        if instrument_type in ["mutualfund", "stock", "index", "future", "bond"]:
            return self.ths_database.Get_Instruments_DataFrame(instrument_type, filter=filter, projection=projection, listed=listed)

    def Get_Daily_Bar(self, symbol, instrument_type, projection=[], datetime1=None, datetime2=None):
        # New Style
        df_bars = self.Get_Daily_Bar_DataFrame(symbol, instrument_type, projection=projection,
                                               datetime1=datetime1, datetime2=datetime2)
        documents = df_bars.to_dict(orient='records')
        return documents

    def Get_Daily_Bar_DataFrame(self, symbol, instrument_type, projection=[], datetime1=None, datetime2=None):
        print("---UniDataInterface::Get_Daily_Bar_DataFrame---", symbol, instrument_type, datetime1, datetime2)
        if instrument_type:
            instrument_type = instrument_type.lower()

        if instrument_type in ["mutualfund", "stock", "index", "future", "bond"]:
            return self.ths_database.Get_Daily_Bar_DataFrame(symbol, instrument_type, projection, datetime1, datetime2)
        elif instrument_type == "simulatefof":
            return self.maa_database.Get_Simulatefof_Daily_Bar_Dataframe(symbol, instrument_type, projection, datetime1, datetime2)
        elif instrument_type == "selfprod":
            return self.maa_database.Get_Selfprod_Daily_Bar_Dataframe(symbol, instrument_type, projection, datetime1, datetime2)
        else:
            return pd.DataFrame()

    def Get_Stock_Daily_Bar_DataFrame(self, symbol, projection=[], datetime1=None, datetime2=None):
        return self.ths_database.GetDataFrame("stock", "dailybar", filter={"symbol": symbol},
                                              projection=projection, datetime1=datetime1, datetime2=datetime2)

    def Get_Mutual_Fund_Daily_Bar(self, symbol, projection=[], datetime1=None, datetime2=None):
        return self.ths_database.GetDataFrame("mutualfund", "dailybar", filter={"symbol": symbol}, projection=projection, datetime1=datetime1, datetime2=datetime2)

    def Get_Index_Daily_Bar(self):
        pass

    def Upsert(self, databaseName, tableName, target, document):
        pass

    def GetDataFrame(self, databaseName, tableName, filter={}, projection=[], datetime1=None, datetime2=None, sort=None):
        pass

    def SaveDataFrame(self, databaseName, tableName, df, save_fields=[]):
        pass


def Test_uni_portfolio(database):
    symbol = "JT-FOF202009240000007919"
    return database.Get_Daily_Bar_DataFrame(symbol, instrument_type="maa_portfolio")


def Test_maa_portfolio(database):
    symbol = "JT-FOF202009240000007919"
    return database.Get_Maa_Portfolio_Daily_Bar_Dataframe(symbol, instrument_type="maa_portfolio")


def Test_uni_data(database):
    symbols = ["JT-FOF202009240000009589", "000001.SZ", "038006.IB", "645"]
    types = ["simulatefof", "stock", "bond", "selfprod"]
    dic = dict(zip(symbols, types))
    for symbol, value in dic.items():
        print(symbol, value)
        df_bars = database.Get_Daily_Bar_DataFrame(symbol, instrument_type=value)
        print(df_bars)


def Test_uni_df(database):
    return database.Get_Instruments_DataFrame(instrument_type="stock")


def Test_Multi_Load(database):
    # symbol_list = ["JT-FOF202009240000009589", "000001.SZ", "038006.IB", "645"]
    # instrument_type_list = ["simulatefof", "stock", "bond", "selfprod"]
    # symbol_list = ["JT-FOF202009240000009589", "000001.SZ", "645"]
    # instrument_type_list = ["simulatefof", "stock", "selfprod"]
    symbol_list = ["JT-FOF202010260000020156", "JT-FOF202010230000017617"]
    instrument_type_list = ["simulatefof", "simulatefof"]
    datetime1 = datetime.datetime(2020,1,1)
    datetime2 = datetime.datetime(2020,10,1)
    df = Load_Multi_DailyBar_DataFrame(database, symbol_list, datetime1, datetime2, instrument_type_list=instrument_type_list)
    print(df)


def Test_Common_Load(database):
    symbol_list = ["038006.IB", "JT-FOF202009240000009589", "000001.SZ",  "645"]
    instrument_type_list = ["bond", "simulatefof", "stock",  "selfprod"]
    dic = dict(zip(symbol_list, instrument_type_list))
    for symbol, instrument_type in dic.items():
        print(symbol, instrument_type)
        df_bars = Common_Load_DailyBar_DataFrame(database, symbol, instrument_type=instrument_type)

        print(df_bars)

if __name__ == '__main__':

    from Core.Config import *
    pathfilename = os.getcwd() + "\..\Config\config_develop.json"
    config = Config(pathfilename)
    database = config.DataBase("Uni")
    # print(Test_uni_portfolio(database))
    # print(Test_uni_df(database))
    # Test_uni_data(database)
    # Test_Common_Load(database)
    Test_Multi_Load(database)

    # database2 = config.DataBase("MAA", config_field="MAADB")
    # print(Test_maa_portfolio(database2))